package com.googlecode.tracey.ui.core;

import com.googlecode.funclate.Model;
import com.googlecode.funclate.stringtemplate.EnhancedStringTemplateGroup;
import com.googlecode.totallylazy.Function1;
import com.googlecode.totallylazy.Xml;
import com.googlecode.utterlyidle.MatchedResource;
import com.googlecode.utterlyidle.Renderer;
import com.googlecode.utterlyidle.handlers.HttpClient;
import com.googlecode.utterlyidle.html.Form;
import com.googlecode.utterlyidle.sitemesh.PageMap;
import com.googlecode.utterlyidle.sitemesh.TemplateName;
import org.antlr.stringtemplate.StringTemplate;

import java.io.PrintWriter;
import java.io.StringWriter;

import static com.googlecode.totallylazy.Predicates.instanceOf;
import static com.googlecode.totallylazy.URLs.packageUrl;

public class ModelRenderer implements Renderer<Model> {
    private final TemplateName templateName;
    private MatchedResource resource;
    private final HttpClient httpHandlerForIncludes;

    public static final String TEMPLATE_NAME = "TEMPLATE_NAME";

    public ModelRenderer(TemplateName templateName, MatchedResource matchedResource, HttpClient httpHandlerForIncludes) {
        this.templateName = templateName;
        resource = matchedResource;
        this.httpHandlerForIncludes = httpHandlerForIncludes;
    }

    public String render(Model model) throws Exception {
        final EnhancedStringTemplateGroup templateGroup = new EnhancedStringTemplateGroup(packageUrl(resource.forClass()));
        templateGroup.registerRenderer(instanceOf(String.class), Xml.escape());
        templateGroup.registerRenderer(instanceOf(Form.class), new Function1<Object, String>() {
            public String call(Object o) throws Exception {
                return o.toString();
            }
        });
        templateGroup.registerRenderer(instanceOf(Throwable.class), new Function1<Object, String>() {
            public String call(Object o) throws Exception {
                Throwable t = (Throwable) o;
                final StringWriter stringWriter = new StringWriter();
                t.printStackTrace(new PrintWriter(stringWriter));
                return "<pre>" + stringWriter.toString() + "</pre>";
            }
        });
        templateGroup.registerRenderer(instanceOf(Svg.class), new Function1<Object, String>() {
            public String call(Object o) throws Exception {
                return ((Svg) o).value();
            }
        });


        final StringTemplate template = templateGroup.getInstanceOf(templateName(model), model.toMap());
        template.setAttribute("include", new PageMap(httpHandlerForIncludes));
        return template.toString();
    }

    private String templateName(Model model) {
        return model.contains(TEMPLATE_NAME) ? model.get(TEMPLATE_NAME, String.class) : templateName.value();
    }
}
